package com.cmwa.solution.utils;

import java.io.File;
import java.io.FileInputStream;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.activation.MimetypesFileTypeMap;
import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.Multipart;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimeUtility;
import javax.mail.util.ByteArrayDataSource;

import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import com.cmwa.solution.sys.attach.entity.FileVo;
import com.cmwa.solution.sys.msg.service.IEmailParameterService;
import com.cmwa.solution.sys.msg.service.impl.EmailParameterServiceImpl;
import com.cmwa.solution.sys.msg.vo.EmailParameterVo;
import com.cmwa.solution.sys.msg.vo.EmailVo;
import com.cmwa.solution.sys.msg.vo.MsgPublicEmailVo;
import com.cmwa.solution.utils.spring.SpringContextUtil;

public class EmailUtil {
	private static Logger log = Logger.getLogger(EmailUtil.class);
	
	public static final String EMAIL_CONTENTTYPE_HTML="TEXT/HTML";
	public static final String EMAIL_CONTENTTYPE_HTML_OUT="TEXT/HTML;CHARSET=GB2312";
	
	private String SMTP_SERVER;
	private String MAIL_ADDRESS;
	private String AUTH_USERNAME;
	private String AUTH_PASSWORD;
	
	private static final String DEF_KEY = "__DEF__KEY__";
	
	private static Map<String, EmailUtil> INSTANCE_MAP = new ConcurrentHashMap<String, EmailUtil>();
	
	public static EmailUtil getInstance(String mailConf) throws Exception {
		if (mailConf == null && INSTANCE_MAP.get(DEF_KEY) == null) {
			EmailUtil emailUtil = new EmailUtil();
			INSTANCE_MAP.put(DEF_KEY, emailUtil);
			load(mailConf);
		}
		if (mailConf != null && INSTANCE_MAP.get(mailConf) == null) {
			EmailUtil emailUtil = new EmailUtil();
			INSTANCE_MAP.put(mailConf, emailUtil);
			load(mailConf);
		}
		return INSTANCE_MAP.get(mailConf == null ? DEF_KEY : mailConf);
	}
	
	public static EmailUtil getInstance() throws Exception {
		return getInstance(null);
	}

	private static void load(String mailConf) throws Exception {
		IEmailParameterService service=(IEmailParameterService)SpringContextUtil.getBean(EmailParameterServiceImpl.class);
		service.setMailConf(mailConf);
		EmailParameterVo vo=service.getEmailParameter();
		EmailUtil e = INSTANCE_MAP.get(mailConf == null?DEF_KEY:mailConf);
		e.SMTP_SERVER=vo.getServer();
		e.MAIL_ADDRESS=vo.getAddress();
		e.AUTH_USERNAME=vo.getUser();
		e.AUTH_PASSWORD=vo.getPassword();
	}

	public void send(EmailVo email) throws Exception {
		log.info("== EmailUtil send(email) start ==");
		InetAddress addr = InetAddress.getLocalHost();
		log.info("== ip:"+ addr.getHostAddress() +" ==");
		log.info("== AUTH_USERNAME:"+ AUTH_USERNAME +" ==");
		log.info("== SMTP_SERVER:"+ SMTP_SERVER +" ==");
		log.info("== MAIL_ADDRESS:"+ MAIL_ADDRESS +" ==");
		Properties props = System.getProperties();
		props.put("mail.smtp.host", SMTP_SERVER);
		props.put("mail.smtp.auth", "true");
		EmailAuth auth = new EmailAuth(AUTH_USERNAME, AUTH_PASSWORD);
		Session session = Session.getInstance(props, auth);
		MimeMessage msg = new MimeMessage(session);
		
		if(StringUtils.isNotBlank(email.getNickName())){
			String nick="";  
			try {  
		            nick=javax.mail.internet.MimeUtility.encodeText(email.getNickName());  
	        } catch (UnsupportedEncodingException e) {  
	            e.printStackTrace();  
	        }   
			msg.setFrom(new InternetAddress(nick+" <"+MAIL_ADDRESS+">")); 
		}else{
			msg.setFrom(new InternetAddress(MAIL_ADDRESS));
		}
		List<String> toList = email.getTo();
		Set<String> toSet = new HashSet<String>();
		toSet.addAll(toList);
		log.info("== EmailUtil send(email) toSet[ "+toSet+" ] ==");
		if (toSet != null && toSet.size()>0) {
			
			ArrayList<InternetAddress> toAddressArr = new ArrayList<InternetAddress>();
			
			Iterator<String> toIt = toSet.iterator();
			
			while (toIt.hasNext()) {
				String tmp_to_emailaddress=toIt.next();
				if(tmp_to_emailaddress!=null && !"".equalsIgnoreCase(tmp_to_emailaddress.trim())){
					toAddressArr.add(new InternetAddress(tmp_to_emailaddress));
				}
			}
			
			if(toAddressArr.size()==0){
				throw new Exception("收件人邮箱不能为空");
			}else{
				InternetAddress[] toAddress = new InternetAddress[toAddressArr.size()];
				toAddressArr.toArray(toAddress);
				msg.setRecipients(Message.RecipientType.TO, toAddress);
			}

		}
		
		
		List<String> ccList = email.getCc();
		if (ccList != null && ccList.size()>0) {
			Set<String> ccSet = new HashSet<String>();
			ccSet.addAll(ccList);
			log.info("== EmailUtil send(email) ccSet[ "+ccSet+" ] ==");
			ArrayList<InternetAddress> ccAddressArr=new ArrayList<InternetAddress>();
			
			Iterator<String> ccIt = ccSet.iterator();
			
			while (ccIt.hasNext()) {
				String tmp_cc_emailaddress=ccIt.next();
				if(tmp_cc_emailaddress!=null && !"".equalsIgnoreCase(tmp_cc_emailaddress.trim())){
					ccAddressArr.add(new InternetAddress(tmp_cc_emailaddress));
				}
			}
			
			if(ccAddressArr.size()!=0){
				InternetAddress[] ccAddress = new InternetAddress[ccAddressArr.size()];
				ccAddressArr.toArray(ccAddress);
				msg.setRecipients(Message.RecipientType.CC, ccAddress);
			}
			
		}
		
		
		List<String> bccList = email.getBcc();
		if (bccList != null && bccList.size()>0) {
			Set<String> bccSet = new HashSet<String>();
			bccSet.addAll(bccList);
			log.info("== EmailUtil send(email) bccSet[ "+bccSet+" ] ==");
			ArrayList<InternetAddress> bccAddressArr = new ArrayList<InternetAddress>();
			
			Iterator<String> bccIt = bccSet.iterator();
			
			while (bccIt.hasNext()) {
				String tmp_bcc_emailaddress=bccIt.next();
				if(tmp_bcc_emailaddress!=null && !"".equalsIgnoreCase(tmp_bcc_emailaddress.trim())){
					bccAddressArr.add(new InternetAddress(tmp_bcc_emailaddress));
				}
			}
			
			if(bccAddressArr.size()!=0){
				InternetAddress[] bccAddress = new InternetAddress[bccAddressArr.size()];
				bccAddressArr.toArray(bccAddress);
				msg.setRecipients(Message.RecipientType.BCC, bccAddress);
			}
			
		}
		
		String subject = email.getSubject();
		msg.setSubject(subject);

		Multipart mp = new MimeMultipart();
		MimeBodyPart mbp1 = new MimeBodyPart();
		//if(email.getIsOut()!=null && "Y".equals(email.getIsOut())||(toList.size() == 1 && !ManualOperationParamsVo.isInnerMail(toList.get(0)))){
			mbp1.setContent(new String(email.getContent().getBytes("ISO-8859-1"),"UTF-8"), EMAIL_CONTENTTYPE_HTML_OUT);
		/*}else{
			mbp1.setContent(email.getContent(), email.getContentType());
		}
		*/
		mp.addBodyPart(mbp1);
		msg.setContent(mp);
		List<Map<String, String>> attachment = email.getAttachment();
		log.info("== EmailUtil send(email) attachment[ "+attachment+" ]  ==");
		
		if (attachment != null) {
			Iterator<Map<String, String>> it = attachment.iterator();
			MimeBodyPart mbp = new MimeBodyPart();
			Map<String, String> map=null;
			for (; it.hasNext(); mp.addBodyPart(mbp)) {
				mbp = new MimeBodyPart();
				map=it.next();
				String absolute_filename = map.get("FILEPATH");
				String attName = map.get("ATTNAME");//拿到附件名字
				log.info("== EmailUtil send(email) attachment one absolute_filename [ "+absolute_filename+" ]  ==");
				
				FileDataSource fds = new FileDataSource(absolute_filename);
				mbp.setDataHandler(new DataHandler(fds));
				String encodedFileName ="";
				/**
				 *取本地附件名字、作为发送附件显示的名字
				 */
				if(BooleanUtils.isTrue(email.getIsTransformFileName())){
//					 encodedFileName = new String(attName.getBytes("UTF-8"), "iso8859-1");
					encodedFileName = MimeUtility.encodeText(attName);
				}else{
//					 encodedFileName = new String(fds.getName().getBytes("UTF-8"), "iso8859-1");
					encodedFileName = MimeUtility.encodeText(fds.getName());
				}
				
				log.info("== EmailUtil send(email) attachment one encodedFileName [ "+encodedFileName+" ]  ==");
				
				mbp.setHeader("Content-ID", encodedFileName);
				mbp.setFileName(encodedFileName);
			}
		}
		/**
		 * 把磁盘中的文件，当成附件发送
		 */
		List<FileVo> attFile = email.getAttFiles();
		if (attFile != null) {
			for (FileVo fileVo : attFile) {
				FileInputStream fis = null;
				File file = fileVo.getFile();
				if (file != null && file.exists()) {
					MimeBodyPart mbp = new MimeBodyPart();
					try {
						fis = new FileInputStream(file);
						String MIME = new MimetypesFileTypeMap().getContentType(file);
						javax.activation.DataSource dataSource = new ByteArrayDataSource(fis, MIME);
						mbp.setDataHandler(new DataHandler(dataSource));
						String fileName = file.getName();
						if (BooleanUtils.isTrue(fileVo.getIsTransformFileName())) {
							fileName = fileVo.getFileRealName();
						}
						//fileName = new String(fileName.getBytes("UTF-8"), "iso8859-1");// 文件在
						
						fileName = MimeUtility.encodeText(fileName);
						
						mbp.setFileName(fileName);
					} catch (Exception e) {
						e.printStackTrace();
					} finally {
						if (fis != null) {
							fis.close();
						}
					}
					mp.addBodyPart(mbp);
				}
			}
		}
		
		msg.setSentDate(new Date());
		try {
			Transport.send(msg);
			log.info("== EmailUtil send(email) Transport [ SUCCESS ]  ==");
		} catch (Exception e) {
			log.info("== EmailUtil send(email) Transport [ Exception ] [ "+e.getMessage()+" ]  ==");
			e.printStackTrace();
			throw new Exception("MailSender." + e);
		}
	}
	
	class EmailAuth extends Authenticator{
		String username;
		String password;
		public EmailAuth(String uname, String pwd) {
			username = uname;
			password = pwd;
		}
		public PasswordAuthentication getPasswordAuthentication() {
			return new PasswordAuthentication(username, password);
		}
	}
	
	//-------------------------------------------------------------------------------------------------------------------------
	
	public static EmailVo createMail(String subject,String contentType,String content,String receiver,List<Map<String,String>> attachment){
		EmailVo email=new EmailVo();
		email.setSubject(subject);
		email.setAttachment(attachment);
		try {
			email.setContent(new String(content.getBytes("UTF-8"), "iso8859-1"));
		} catch (UnsupportedEncodingException e) {
			log.info("== EmailUtil createMail(String ,String ,String ,String ,List<Map<String,String>>) Exception [ "+e.getMessage()+" ] ==");
			e.printStackTrace();
		}
		email.setContentType(contentType);
		email.addTo(receiver);
		return email;
	}
	public static EmailVo createMail(String subject,String contentType,String content,String[] receivers,List<Map<String,String>> attachment){
		EmailVo email=new EmailVo();
		email.setSubject(subject);
		email.setAttachment(attachment);
		try {
			email.setContent(new String(content.getBytes("UTF-8"), "iso8859-1"));
		} catch (UnsupportedEncodingException e) {
			log.info("== EmailUtil createMail(String ,String ,String ,String[] ,List<Map<String,String>>) Exception [ "+e.getMessage()+" ] ==");
			e.printStackTrace();
		}
		email.setContentType(contentType);
		email.addTo(Arrays.asList(receivers));
		return email;
	}
	
	//-------------------------------------------------------------------------------------------------------------------------
	
	public static String sendMail(String subject,String contentType,String content,String receiver,List<Map<String,String>> attachment) throws Exception{
		EmailVo email=new EmailVo();
		
		email.setSubject(subject);
		email.setAttachment(attachment);
		try {
			email.setContent(new String(content.getBytes("UTF-8"), "iso8859-1"));
		} catch (UnsupportedEncodingException e) {
			log.info("== EmailUtil sendMail(String ,String ,String ,String ,List<Map<String,String>>) Exception [ "+e.getMessage()+" ] ==");
			e.printStackTrace();
		}
		email.setContentType(contentType);
		email.addTo(receiver);
		return sendMail(email);
	}
	
	public static String sendMail(String subject,String contentType,String content,String[] receivers,List<Map<String,String>> attachment) throws Exception{
		EmailVo email=new EmailVo();
		email.setSubject(subject);
		email.setAttachment(attachment);
		try {
			email.setContent(new String(content.getBytes("UTF-8"), "iso8859-1"));
		} catch (UnsupportedEncodingException e) {
			log.info("== EmailUtil sendMail(String ,String ,String ,String[] ,List<Map<String,String>>) Exception [ "+e.getMessage()+" ] ==");
			e.printStackTrace();
		}
		email.setContentType(contentType);
		email.addTo(Arrays.asList(receivers));
		return sendMail(email);
	}
	
	/**
	 *  取本地附件名字、作为发送附件显示的名字
	 * @param subject
	 * @param contentType
	 * @param content
	 * @param receivers
	 * @param cc
	 * @param attachment
	 * @return
	 */
	public static String sendMail(String nickName,String thirdAddressor,String subject,String contentType,String content,String[] receivers,String[] cc,List<Map<String,String>> attachment,List<FileVo> attFiles) throws Exception{
		EmailVo email=new EmailVo();
		email.setSubject(subject);
		email.setAttachment(attachment);
		try {
			email.setContent(new String(content.getBytes("UTF-8"), "iso8859-1"));
		} catch (UnsupportedEncodingException e) {
			log.info("== EmailUtil sendMail(String ,String ,String ,String[] ,String[] ,List<Map<String,String>>) Exception [ "+e.getMessage()+" ] ==");
			e.printStackTrace();
		}
		email.setNickName(nickName);
		email.setContentType(contentType);
		email.addTo(Arrays.asList(receivers));
		email.addCc(Arrays.asList(cc));
		email.setIsTransformFileName(true);
		email.setAttFiles(attFiles);
		return sendMail(email,thirdAddressor);
	}
	
	public static String sendMail(String thirdAddressor,String subject,String contentType,String content,String[] receivers,String[] cc,List<Map<String,String>> attachment, List<FileVo> attFiles) throws Exception{
		return sendMail(null, thirdAddressor, subject, contentType, content, receivers, cc, attachment, attFiles);
	}
	
	
	public static String sendMailOut(String subject,String contentType,String content,String[] receivers,String[] cc,List<Map<String,String>> attachment, List<FileVo> attFiles) throws Exception{
		EmailVo email=new EmailVo();
		email.setSubject(subject);
		email.setAttachment(attachment);
		email.setIsOut("Y");
		try {
			email.setContent(new String(content.getBytes("UTF-8"), "iso8859-1"));
		} catch (UnsupportedEncodingException e) {
			log.info("== EmailUtil sendMail(String ,String ,String ,String[] ,String[] ,List<Map<String,String>>) Exception [ "+e.getMessage()+" ] ==");
			e.printStackTrace();
		}
		email.setContentType(contentType);
		email.addTo(Arrays.asList(receivers));
		email.addCc(Arrays.asList(cc));
		email.setAttFiles(attFiles);
		return sendMail(email);
	}
	
	public static String sendMail(EmailVo email) throws Exception{
		log.info("== EmailUtil sendMail[Pack] start ==");
		String msg="SUCCESS";
		try {
			EmailUtil.getInstance().send(email);
		} catch (Exception e) {
			log.info("== EmailUtil sendMail[Pack] Exception[ "+e.getMessage()+" ] ==");
			msg=ExceptionUtil.obtainStackTrace(e);
			e.printStackTrace();
			throw e;
		}
		return msg;
	}
	
	public static String sendMail(EmailVo email,String mailConf) throws Exception {
		log.info("== EmailUtil sendMail[Pack] start ==");
		String msg="SUCCESS";
		try {
			if(StringUtils.isNotBlank(mailConf))
				EmailUtil.getInstance(mailConf).send(email);
			else{
				EmailUtil.getInstance().send(email);
			}
		} catch (Exception e) {
			log.info("== EmailUtil sendMail[Pack] Exception[ "+e.getMessage()+" ] ==");
			msg=ExceptionUtil.obtainStackTrace(e);
			e.printStackTrace();
			throw e;
		}
		return msg;
	}
	
	
	public static List<String> findPubEmailAddressByEmailVos(List<MsgPublicEmailVo> vos){
		List<String> rst=new ArrayList<String>();
		if(vos!=null){
			for(MsgPublicEmailVo one: vos){
				rst.add(one.getEmail());
			}
		}
		return rst;
	}
	public static List<String> findPubEmailIdByEmailVos(List<MsgPublicEmailVo> vos){
		List<String> rst=new ArrayList<String>();
		if(vos!=null){
			for(MsgPublicEmailVo one: vos){
				rst.add(one.getId());
			}
		}
		return rst;
	}
	
	public static List<String> findEmailByEmpId(List<String> empIds,List<Map<String, String>> kv){
		List<String> rst=new ArrayList<String>();
		for(String empId : empIds){
			
			for(Map<String, String> m : kv){
				String tmpId=StringUtils.trimToEmpty(m.get("EMPID"));
				String tmpEmail=StringUtils.trimToEmpty(m.get("EMPEMAIL"));
				
				if(empId.equalsIgnoreCase(tmpId)){
					if(!"".equalsIgnoreCase(tmpEmail.trim())){
						rst.add(tmpEmail);
					}
					break;
				}
				
			}
			
		}
		return rst;
	}
}
